package com.zusmart.core.bean.support;

import java.lang.reflect.Method;

import com.zusmart.base.logging.Logger;
import com.zusmart.base.logging.LoggerFactory;
import com.zusmart.base.util.Assert;
import com.zusmart.base.util.ReflectionUtils;
import com.zusmart.core.bean.BeanDefinition;
import com.zusmart.core.bean.BeanDefinitionResolver;
import com.zusmart.core.bean.BeanInstanceHandler;
import com.zusmart.core.bean.cause.BeanInstanceCreateException;
import com.zusmart.core.bean.cause.BeanInstanceDestoryException;
import com.zusmart.core.bean.cause.BeanInstanceInitialException;
import com.zusmart.core.bean.cause.BeanInstanceInjectException;
import com.zusmart.core.bean.cause.BeanInstanceReleaseException;

public abstract class AbstractBeanInstanceHandler implements BeanInstanceHandler {

	private static final Logger logger = LoggerFactory.getLogger(AbstractBeanInstanceHandler.class);

	private final BeanDefinition beanDefinition;
	private final BeanDefinitionResolver beanDefinitionResolver;

	protected AbstractBeanInstanceHandler(BeanDefinition beanDefinition) {
		Assert.isNull(beanDefinition, "bean definition must not be null");
		this.beanDefinition = beanDefinition;
		this.beanDefinitionResolver = beanDefinition.getBeanDefinitionResolver();
	}

	@Override
	public void doCreate() throws BeanInstanceCreateException {

	}

	@Override
	public void doInject() throws BeanInstanceInjectException {

	}

	@Override
	public void doInitial() throws BeanInstanceInitialException {

	}

	@Override
	public void doRelease() throws BeanInstanceReleaseException {

	}

	@Override
	public void doDestory() throws BeanInstanceDestoryException {

	}

	@Override
	public BeanDefinition getBeanDefinition() {
		return this.beanDefinition;
	}

	protected void doInjectFields(Object beanInstance) throws BeanInstanceInjectException {
		BeanDefinition beanDefinition = this.getBeanDefinition();
		if(beanDefinition.isObjectType() || beanDefinition.isMethodType()){
			this.beanDefinitionResolver.injectField(beanInstance.getClass(), beanInstance);
		}else{
			this.beanDefinitionResolver.injectField(beanDefinition.getBeanClass(), beanInstance);
		}
	}

	protected void doInjectMethods(Object beanInstance) throws BeanInstanceInjectException {
		BeanDefinition beanDefinition = this.getBeanDefinition();
		if(beanDefinition.isObjectType() || beanDefinition.isMethodType()){
			this.beanDefinitionResolver.inejctMethod(beanInstance.getClass(), beanInstance);
		}else{
			this.beanDefinitionResolver.inejctMethod(beanDefinition.getBeanClass(), beanInstance);
		}
	}

	protected void doInvokeInitialMethods(Object beanInstance) {
		Method[] methods = this.beanDefinitionResolver.getInitialMethod(beanInstance.getClass());
		if (null == methods || methods.length == 0) {
			return;
		}
		for (int i = 0; i < methods.length; i++) {
			try {
				Method method = methods[i];
				Object[] arguments = beanDefinitionResolver.getBeanArguments(method);
				ReflectionUtils.invokeMethod(method, beanInstance, arguments);
			} catch (Exception e) {
				logger.warn("invoke destory method failed {}", e.getMessage());
			}
		}
	}

	protected void doInovkeDestoryMethods(Object beanInstance) {
		Method[] methods = this.beanDefinitionResolver.getDestoryMethod(beanInstance.getClass());
		if (null == methods || methods.length == 0) {
			return;
		}
		for (int i = 0; i < methods.length; i++) {
			try {
				Method method = methods[i];
				Object[] arguments = beanDefinitionResolver.getBeanArguments(method);
				ReflectionUtils.invokeMethod(method, beanInstance, arguments);
			} catch (Exception e) {
				logger.warn("invoke destory method failed {}", e.getMessage());
			}
		}
	}

}